/****************************************************************************

****************************************************************************/
#include <QtGui>
#include <QStack>

#include "treeitem.h"
#include "treemodel.h"

TreeModel::TreeModel(const QStringList &headers,ViewType viewType, QObject *parent)
    : QAbstractItemModel(parent)
    , _viewType(viewType)
{
    QVector<QVariant> rootData;
    foreach (QString header, headers)
        rootData << header;

    rootItem = new TreeItem(rootData);
}

TreeModel::~TreeModel()
{
    delete rootItem;
}

int TreeModel::columnCount(const QModelIndex & /* parent */) const
{
    return rootItem->columnCount();
}

QVariant TreeModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();

    if (role != Qt::DisplayRole 
        && role != Qt::EditRole 
        // && role != Qt::DecorationRole
        && role != Qt::CheckStateRole
        /*&& role != Qt::UserRole*/){
        return QVariant();
    }

    TreeItem *item = getItem(index);
    if (0 == index.column() && Qt::CheckStateRole == role){
        if (checkSwitch(index))
        {
            return static_cast<int>( item->isChecked() ? Qt::Checked : Qt::Unchecked );
        }else{
            return QVariant();
        }
    }

    // if(0 == index.column() && Qt::DecorationRole == role ){
    //     return QVariant(ToIcon(IconType(item->getIcon().toInt())
    //         ,ToIconState(item->getState().toInt())));
    // }

    if( Qt::DisplayRole == role || Qt::EditRole == role  ){
        return item->data(index.column());  
    }

    return QVariant();
}

QVariant TreeModel::getIconFlags(const QModelIndex &index) const
{
    if (!index.isValid())
        return QVariant();
    TreeItem *item = getItem(index);
    if(0 == index.column())
    {
        return item->getIcon();
    }
    return QVariant();
}

Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{
    if (!index.isValid())
        return 0;

    /*
    **if it is first colum , make it has checkbox ability
    */
    if (checkSwitch(index) && index.column()==0)
        return Qt::ItemIsEnabled 
            | Qt::ItemIsSelectable 
            | Qt::ItemIsUserCheckable; 
    if (index.column()==1&&0==rowCount(index))
        return Qt::ItemIsEditable 
            | Qt::ItemIsEnabled 
            | Qt::ItemIsSelectable; 

    return Qt::ItemIsEnabled 
        | Qt::ItemIsSelectable;
}

TreeItem *TreeModel::getItem(const QModelIndex &index) const
{
	if (!index.isValid()) 
		return rootItem;
	if(rootItem->isEmpty())
		return rootItem;

	TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
	if (item)
		if(item->parent())	
			return item;
	return rootItem;
}


QVariant TreeModel::headerData(int section, Qt::Orientation orientation,
                               int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
        return rootItem->data(section);
    if (orientation == Qt::Vertical && role == Qt::DisplayRole)
        return QVariant(section);
    return QVariant();
}

QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const
{
    if (parent.isValid() && parent.column() != 0)
        return QModelIndex();
	if(rootItem->isEmpty())
		return QModelIndex();
    TreeItem *parentItem = getItem(parent);
    TreeItem *childItem = parentItem->child(row);
    if (childItem)
        return createIndex(row, column, childItem);
    else
        return QModelIndex();
}

QModelIndex TreeModel::parent(const QModelIndex &index) const
{
    if (!index.isValid())
        return QModelIndex();
	if(rootItem->isEmpty())
		return QModelIndex();

    TreeItem *childItem = getItem(index);
	if (childItem == rootItem)
		return QModelIndex();

    TreeItem *parentItem = childItem->parent();
    if (parentItem == rootItem)
        return QModelIndex();

    return createIndex(parentItem->childNumber(), 0, parentItem);
}

bool TreeModel::insertColumns(int position, int columns, const QModelIndex &parent)
{
    bool success;

    beginInsertColumns(parent, position, position + columns - 1);
    success = rootItem->insertColumns(position, columns);
    endInsertColumns();

    return success;
}

bool TreeModel::insertRows(int position, int rows, const QModelIndex &parent)
{
    // qDebug()<<"position = "<<position<<","<<"rows = "<< rows<<"parent = "<<parent.data().toString();
    TreeItem *parentItem = getItem(parent);
    bool success;

    beginInsertRows(parent, position, position + rows - 1);
    success = parentItem->insertChildren(position, rows, rootItem->columnCount());
    endInsertRows();

    return success;
}

bool TreeModel::removeColumns(int position, int columns, const QModelIndex &parent)
{
    bool success;

    beginRemoveColumns(parent, position, position + columns - 1);
    success = rootItem->removeColumns(position, columns);
    endRemoveColumns();

    if (rootItem->columnCount() == 0)
        removeRows(0, rowCount());

    return success;
}

bool TreeModel::removeRows(int position, int rows, const QModelIndex &parent)
{
    TreeItem *parentItem = getItem(parent);
    bool success = true;

    beginRemoveRows(parent, position, position + rows - 1);
    success = parentItem->removeChildren(position, rows);
    endRemoveRows();

    return success;
}

int TreeModel::rowCount(const QModelIndex &parent) const
{
    TreeItem *parentItem = getItem(parent);

    return parentItem->childCount();
}

bool TreeModel::setData(const QModelIndex &index, 
    const QVariant &value,int role)
{
    if (role != Qt::EditRole 
        // && role != Qt::DecorationRole 
        && role != Qt::CheckStateRole
        && role != Qt::UserRole)
        return false;

    if(0 == index.column() && Qt::CheckStateRole == role ){
        if(!checkSwitch(index))//jude this item is check endable
            return false;
        //neet check it's child and set their check state too
        // bool isCheck = (value==Qt::Checked?true : false);
        bool isCheck = (bool)(value==Qt::Checked);
        TreeItem *item = getItem(index);
            
        if(item->isChecked()!=isCheck){
            item->setCheckState(isCheck);
            emit dataChanged(index, index);

            int childCol = this->rowCount(index);
            if(childCol>0){
                for(int i=0; i<childCol; i++)
                    this->setData(this->index(i,0,index),value,Qt::CheckStateRole);
            }
            rptSetDeal(index,value);
        }
        return true;
    }

    // if(0==index.column() && Qt::DecorationRole == role ){
    //     TreeItem *item = getItem(index);
    //     item->setIcon(value);
    //     emit dataChanged(index, index);
    //     return true;
    // }

    if (Qt::EditRole == role )
    {
		TreeItem *item = getItem(index);
		if(item!=rootItem){
			if(item->data(index.column()).toString()!=value.toString()){
				item->setData(index.column(), value);
				emit dataChanged(index, index);
				// qDebug()<<item->data(index.column())<<"$$$$$$$$$$$$$$$$$$$$$$$$$$ \n";
				return true;
			}
		}
    }

    if (Qt::UserRole == role )
    {
        TreeItem *item = getItem(index);
        item->setState(value);
        emit dataChanged(index, index);
        return true;       
    }

    return false;
}

void TreeModel::rptSetDeal(const QModelIndex &index,const QVariant &value)
{
    int level = 0;
    QModelIndex _parentIndex = typeCurrentIndexParent(index,level);
    if (_parentIndex.data().toString()=="mms_server")
    {
        if (5==level)
        {
            QStringList varStrList;
            QModelIndex _index = index;
            while(QModelIndex()!=_index){
                varStrList.prepend(_index.data().toString());
                _index = this->parent(_index);
            }
            if(varStrList.size()!=5)
                return;
            QStringList rptStrList;
            rptStrList.append("rptcb_server");
            rptStrList.append(varStrList[1]);
            QString _flatName = varStrList[2]+"$"+varStrList[3]+"$"+varStrList[4];
            rptStrList.append(_flatName);
            QModelIndex  rpt_index = this->findIndex(rptStrList);
            if(QModelIndex()!=rpt_index)
                this->setData(rpt_index,value,Qt::CheckStateRole);
        }
        if(4==level){
            QStringList varStrList;
            QModelIndex _index = index;
            while(QModelIndex()!=_index){
                varStrList.prepend(_index.data().toString());
                _index = this->parent(_index);
            }
            if(varStrList.size()!=4)
                return;
            
            QString _str = varStrList.takeLast();
            if("RP"==_str){
                varStrList.append("BR");
            }else if("BR"==_str){
                varStrList.append("RP");
            }else{
                return;
            }

            int _isCheckAll = 0;
            QModelIndex  _index_br_rp = this->findIndex(varStrList);
            if(value==this->data(_index_br_rp,Qt::CheckStateRole)){
                _isCheckAll = 1;
            }else{
                if(value==QVariant(Qt::Unchecked))
                    _isCheckAll = 2;
            }

            if(_isCheckAll>0){
                QStringList rptStrList;
                rptStrList.append("rptcb_server");
                rptStrList.append(varStrList[1]);
                QModelIndex  rpt_index = this->findIndex(rptStrList);
                if(QModelIndex()!=rpt_index)
                    this->setData(rpt_index,value,Qt::CheckStateRole);  
            }
            if(2==_isCheckAll){
                this->setData(_index_br_rp,QVariant(Qt::Checked),Qt::CheckStateRole);  
            }
        }
    }
    if (_parentIndex.data().toString()=="rptcb_server")
    {
        if (3==level)
        {
            QStringList varStrList;
            QModelIndex _index = index;
            while(QModelIndex()!=_index){
                varStrList.prepend(_index.data().toString());
                _index = this->parent(_index);
            }
            if(varStrList.size()!=3)
                return;
            QStringList mmsStrList;
            mmsStrList.append("mms_server");
            mmsStrList.append(varStrList[1]);
            QStringList _msList = varStrList[2].split("$",QString::SkipEmptyParts);
            if(_msList.size()!=3)
                return;
            mmsStrList.append(_msList[0]);
            mmsStrList.append(_msList[1]);
            mmsStrList.append(_msList[2]);
            QModelIndex  mms_index = this->findIndex(mmsStrList);
            if(QModelIndex()!=mms_index)
                this->setData(mms_index,value,Qt::CheckStateRole);
        }

        if (2==level)
        {
            QStringList varStrList;
            QModelIndex _index = this->index(0,0,index);
            while(QModelIndex()!=_index){
                varStrList.prepend(_index.data().toString());
                _index = this->parent(_index);
            }
            if(varStrList.size()!=3)
                return;
            QStringList mmsStrList;
            mmsStrList.append("mms_server");
            mmsStrList.append(varStrList[1]);
            QStringList _msList = varStrList[2].split("$",QString::SkipEmptyParts);
            if(_msList.size()!=3)
                return;
            mmsStrList.append(_msList[0]);
            mmsStrList.append("RP");
            QModelIndex  mms_index_rp = this->findIndex(mmsStrList);
            if(QModelIndex()!=mms_index_rp)
                this->setData(mms_index_rp,value,Qt::CheckStateRole);
            mmsStrList.pop_back();
            mmsStrList.append("BR");
            QModelIndex  mms_index_br = this->findIndex(mmsStrList);
            if(QModelIndex()!=mms_index_br)
                this->setData(mms_index_br,value,Qt::CheckStateRole);
        }
    }
}

bool TreeModel::setHeaderData(int section, Qt::Orientation orientation,
                              const QVariant &value, int role)
{
    if (role != Qt::EditRole || orientation != Qt::Horizontal)
        return false;

    bool result = rootItem->setData(section, value);

    if (result)
        emit headerDataChanged(orientation, section, section);

    return result;
}

bool TreeModel::insertItem(QVector<QVariant> Data, 
    QVariant parent /*,QVariant itemType ,bool isCheck*/ )
{
    bool ret = true;  
    if(QVariant()==parent){
        // qDebug()<<"parent = "<<QModelIndex().data().toString();
        insertItemToParent(QModelIndex(),Data/*,itemType,isCheck*/);    
    }else{
        if(QModelIndex()==getModelIndex(parent)){
            ret = false;
        }else{
            insertItemToParent(getModelIndex(parent),Data/*,itemType,isCheck*/);
        }  
    }

    return ret;
}

bool TreeModel::insertItem(QStringList &parent, 
    QVector<QVariant> Data/*,QVariant itemType ,bool isCheck*/ )
{
    QModelIndex parentIndex = QModelIndex();
    for(int i=0; i<parent.size(); i++){
        QVector<QVariant> Data_t;
        Data_t<<parent.at(i);
        this->insertItemToParent(parentIndex,Data_t/*,itemType*/);
        parentIndex = this->indexChild(QVariant(parent.at(i)),parentIndex);
        if(QModelIndex()==parentIndex){
            // qDebug()<<parentIndex.data().toString();
            return false;
        }
    }

    this->insertItemToParent(parentIndex,Data/*,itemType,isCheck*/);
    return true;
}

bool TreeModel::removeItem(const QVariant treeIndex)
{
    bool ret = true;
    // qDebug()<<treeIndex.toString();
    QModelIndex index = getModelIndex(treeIndex);
    
    if(index.isValid()){
        // qDebug()<<index.data().toString() <<","<<index.row();
        this->removeRow(index.row(), index.parent());
    }else{
        ret = false;
    }

    return ret;
}
void TreeModel::insertItemToParentBefore(const QModelIndex &index,QVector<QVariant> Data)
{
    if (this->columnCount(index) == 0) {
        if (!this->insertColumn(0, index))
            return;
    }
    int pos = 0;
    //insert a new row
    if (!this->insertRow(pos, index))
        return;
    //set the new row's value
    for (int column = 0; column < this->columnCount(index); ++column) {
        QModelIndex child = this->index(pos, column, index);
        this->setData(child,
            column<Data.size()?Data[column].toString():QVariant(""), Qt::EditRole);
    }
}

void TreeModel::insertItemToParent(const QModelIndex &index, 
    QVector<QVariant> Data/*, QVariant itemType ,bool isCheck*/)
{
    if (this->columnCount(index) == 0) {
        if (!this->insertColumn(0, index))
            return;
    }
    int pos = this->rowCount(index);
    //now jude the childs has contain the child;
    bool insertFlag = false;
    //now jude the childs has contain the child;
    if (SA_View==_viewType)
    {
        insertFlag=true;
    }else{
        TreeItem *parentItem = getItem(index);
        if(!parentItem->contains(Data[0])){
            insertFlag=true;
        }else{
            //this means change the child value
            pos = parentItem->indexChild(Data[0]);
            if (pos==-1)
            {
                return;
            }
        }
    }
    if (insertFlag)
    {
        //insert a new row
        if (!this->insertRow(pos, index))
            return;
    }

    // qDebug()<<Data.at(0);
    //set the new row's value
    for (int column = 0; column < this->columnCount(index); ++column) {
        QModelIndex child = this->index(pos, column, index);
        this->setData(child, 
            column<Data.size()?Data[column].toString():QVariant(""), Qt::EditRole);
        if (!this->headerData(column, Qt::Horizontal).isValid())
            this->setHeaderData(column, Qt::Horizontal, 
                column<Data.size()?Data[column].toString():QVariant(""),Qt::EditRole);
        //set the icon 
        // if(0==column){
        //     // if(isCheck)
        //     //     this->setData(child,Qt::Unchecked, Qt::CheckStateRole); 
        //     // else
        //     //     this->setData(child,itemType, Qt::DecorationRole); 
        //     int level  = 0;
        //     QModelIndex fparent = typeCurrentIndexParent(child,level);
        //     this->setData(child,
        //         QVariant(int(ToIconType(fparent.data().toString(),level,child.data().toString()))), 
        //         Qt::DecorationRole); 
        // }
    }
}

void TreeModel::insertItemToParent(const QModelIndex &index,
    QVector< QVector<QVariant> > Datas/*, QVariant itemType ,bool isCheck*/,bool upf)
{
    if (this->columnCount(index) == 0) {
        if (!this->insertColumn(0, index))
            return;
    }
    int pos = this->rowCount(index);

    //insert rows
    if (!this->insertRows(pos, Datas.size(),index))
        return;
    //set the new row's value
    int _role = upf?Qt::EditRole:Qt::UserRole;
    int clcount = this->columnCount(index);
    for (int i = 0; i < Datas.size(); i++)
    {
        for (int column = 0; column < clcount; column++) {
            QModelIndex child = this->index(pos+i, column, index);
            this->setData(child,
                column<Datas[i].size()?Datas[i][column].toString():QVariant(""), _role);
        }
    }
};

//the match item maybe exist some, but return the first be finded
QModelIndex TreeModel::getModelIndex(const QVariant treeIndex)
{
    QQueue<QModelIndex> _indexQueue;
    for(int i=0; i<rowCount(); i++){
        _indexQueue.enqueue(index(i,0));
    }

    while(!_indexQueue.isEmpty()){
        if(_indexQueue.head().data().toString()==treeIndex.toString()){
            return _indexQueue.head();
        }else{
            for(int i=0; i<this->rowCount(_indexQueue.head()); i++)
                _indexQueue.enqueue(_indexQueue.head().child(i,0));
            _indexQueue.dequeue();
        }
    }

    return QModelIndex();
}

QModelIndex TreeModel::indexChild(QVariant childTreeData,
      const QModelIndex &parent) const
{
    if (parent.isValid() && parent.column() != 0)
        return QModelIndex();

    TreeItem *parentItem = getItem(parent);
	int chRow = parentItem->indexChild(childTreeData);
    TreeItem *childItem = parentItem->child(chRow);
    if (childItem)
        return createIndex(chRow, 0, childItem);
    else
        return QModelIndex();
}

QModelIndex TreeModel::findIndex(QStringList &treeFalgs)
{
    QModelIndex index = QModelIndex();
    for(int i=0; i<treeFalgs.size(); i++){
        index = this->indexChild(treeFalgs.at(i),index);
        if(QModelIndex()==index)
            break;
    }

    return index;    
}

bool TreeModel::checkSwitch( const QModelIndex &index ) const
{
    int level = 0;
    QModelIndex findex = typeCurrentIndexParent(index,level);
    //only the client_item's child and rptcb_server item has check_able
    // if(("client" == findex.data().toString() && level > 1)
    //     || ("rptcb_server" == findex.data().toString() && level > 0 ))
    if(("rptcb_server" == findex.data().toString() && level > 0 ))
    {
        return (level>1&&level<4);
    }else if(("mms_server" == findex.data().toString() && level > 0 )){
        if(4==level){
            return ("RP" == index.data().toString()
                || "BR" == index.data().toString());
        }
        if(5==level){
            return ("RP" == index.parent().data().toString()
                || "BR" == index.parent().data().toString());
        }
        return false;
    }else{
        return false;
    }
}

//find the remote parent of a design item
QModelIndex TreeModel::typeCurrentIndexParent(QModelIndex index,int &level) const
{
    QModelIndex parentIndex = index;
    level = 1;
    while(QModelIndex()!=this->parent(parentIndex)){
        parentIndex = this->parent(parentIndex);
        level+=1;
    }

    return parentIndex;
}

//only column = 0 child QModelIndex be check, and by layer
QVector<QModelIndex > TreeModel::findAllChild_layer(const QModelIndex &parent )
{
    QVector<QModelIndex > val;
    QQueue<QModelIndex> _indexQueue;
    if(QModelIndex()==parent)
    {
        for(int i=0; i<rowCount(); i++){
            QModelIndex index_r = index(i,0);
            _indexQueue.enqueue(index_r);
        }
    }
    else{
        _indexQueue.enqueue(parent);
    }

    while(!_indexQueue.isEmpty()){
        val.push_back(_indexQueue.head());
        int rowC = this->rowCount(_indexQueue.head());
        if(rowC>0){
            for(int i=0; i<rowC; i++)
                _indexQueue.enqueue(_indexQueue.head().child(i,0));
        }
        _indexQueue.dequeue();
    } 
    return val;   
}

//only column = 0 child QModelIndex be check, and by order in table
QVector<QModelIndex > TreeModel::findAllChild_order(const QModelIndex &parent )
{
    QVector<QModelIndex > val;
    QStack<QModelIndex> _indexStack;
    if(QModelIndex()==parent)
    {
        for(int i=(rowCount()-1); i>=0; i--){
            QModelIndex index_r = index(i,0);
            _indexStack.push(index_r);
        }
    }else{
        _indexStack.push(parent);
    }

    while(!_indexStack.isEmpty()){
        QModelIndex index_f = _indexStack.pop();
        int rowC = this->rowCount(index_f);
        if(rowC>0){
            for(int i=(rowC-1); i>=0; i--)
                _indexStack.push(index_f.child(i,0));
        }
        val.push_back(index_f);
    } 
    return val;
}
